/*
 * <h3>Title:wheel-parent系统</h3>
 * <p>Copyright (c) 2019, wnfbx@163.com. All rights reserved.</p>
 * @author wnfbx@163.com
 */
package com.wheel.autoconfigure.dynamicdatasource;

import com.wheel.autoconfigure.dynamicdatasource.annotation.DynamicDataSourceKey;
import com.wheel.autoconfigure.dynamicdatasource.aop.DynamicDataSourceAnnotationInterceptor;
import com.wheel.autoconfigure.dynamicdatasource.builder.DynamicDataSourceBuilder;
import com.wheel.autoconfigure.dynamicdatasource.datasource.DynamicRoutingDataSource;
import com.wheel.core.utils.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.ComposablePointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;

/**
 * <dt>Description:DynamicDataSourceAutoConfiguration</dt>
 * <dd>动态数据源自动配置中心</dd>
 *
 * @author wnfbx@163.com
 * @version 1.0 <i>2019/12/15 14:38</i>
 * @since jdk1.7+
 */
@Configuration
@PropertySource({"classpath:application-dynamicDS.properties"})
@ConditionalOnClass(AbstractRoutingDataSource.class)
@AutoConfigureBefore({org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration.class,
        org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration.class,
        org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration.class})
@ConditionalOnMissingBean(DataSource.class)
public class DynamicDataSourceAutoConfiguration {

    private static final Logger log = LoggerFactory.getLogger(DynamicDataSourceAutoConfiguration.class);

    public DynamicDataSourceAutoConfiguration() {
        Log.registered(log);
    }

    @EnableConfigurationProperties(DynamicDataSourceProperties.class)
    public static class DynamicDataSourceConfiguration {

        public DynamicDataSourceConfiguration() {
            Log.registered(log);
        }

        @Bean
        public DynamicDataSourceBuilder dynamicDataSourceBuilder(DynamicDataSourceProperties dynamicDataSourceProperties) {
            return new DynamicDataSourceBuilder(dynamicDataSourceProperties).build();
        }

        @Bean
        public DataSource dynamicRoutingDataSource(DynamicDataSourceBuilder dynamicDataSourceBuilder) {
            return new DynamicRoutingDataSource(dynamicDataSourceBuilder);
        }

        /**
         * <dt>Description:defaultPointcutAdvisor</dt>
         * <dd>使用动态数据源注解拦截器，处理注解
         * 注：spring内部方法互相调用需要获得代理对象，参考<br>
         * com.wheel.autoconfigure.dynamicdatasource.aop.This.proxy
         * 并且启用 @EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true)
         * </dd>
         * <dd>author: wnfbx@163.com</dd>
         * <dd>version:1.0 <i>2020/1/9 14:19</i></dd>
         *
         * @return org.springframework.aop.support.DefaultPointcutAdvisor
         * @since jdk1.7+
         */
        @Bean
        public DefaultPointcutAdvisor defaultPointcutAdvisor(DynamicDataSourceBuilder dynamicDataSourceBuilder) {
            // 配置增强类advisor
            DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
            //checkInherited whether to also check the superclasses and interfaces
            Pointcut classPointcut = new AnnotationMatchingPointcut(DynamicDataSourceKey.class, true);
            Pointcut methodPointcut = AnnotationMatchingPointcut.forMethodAnnotation(DynamicDataSourceKey.class);
            advisor.setPointcut(new ComposablePointcut(classPointcut).union(methodPointcut));
            advisor.setAdvice(new DynamicDataSourceAnnotationInterceptor(dynamicDataSourceBuilder));
            return advisor;
        }
    }
}
